package com.qf.shop.auth.controller;

import com.alibaba.fastjson.JSON;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.qf.shop.auth.feign.api.CarService;
import com.qf.shop.auth.feign.api.UserService;
import com.qf.shop.common.constants.AuthConstants;
import com.qf.shop.common.constants.RabbitMQCons;
import com.qf.shop.common.constants.RedisConstatns;
import com.qf.shop.common.exception.BusinessException;
import com.qf.shop.common.utils.JWTUtils;
import com.qf.shop.common.utils.R;
import com.qf.shop.common.vo.Email;
import com.qf.shop.common.vo.SmsVo;
import com.qf.shop.common.vo.UserVo;
import com.wf.captcha.utils.CaptchaUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.User;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

//@Controller @Service @Repository @Bean @Configuration
@RestController // <Bean>
@RequestMapping("/auth")
@Slf4j
public class AuthController {

    @Autowired
    private UserService userService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private CarService carService;

    @PostMapping("/check")
    public Map<String, Object> checkUsername(@RequestParam("name") String filed, @RequestParam("param") String value) {

        Map<String, Object> map = new HashMap<>();


        if (StringUtils.isEmpty(filed)) {
            map.put("status", "n"); // 失败
            map.put("info", "字段名称为空"); // 失败
            return map;
        }
        if (StringUtils.isEmpty(value)) {
            map.put("status", "n"); // 失败
            map.put("info", "用户名为空"); // 失败
            return map;
        }

        // 1.查询用户是否已进被注册
        UserVo user = userService.findUser(filed, value);
        if (user == null) {
            map.put("status", "y"); // 失败
            map.put("info", "用户名可以注册"); // 失败
        } else {
            map.put("status", "n"); // 失败
            if ("username".equals(filed)) {
                map.put("info", "用户名已被注册"); // 失败
            } else if ("email".equals(filed)) {
                map.put("info", "邮箱已被注册"); // 失败
            }
        }
        return map;

    }

    @GetMapping("/sendPhoneCode/{mobile}")
    public void sendPhoneCode(@PathVariable String mobile) {

        //1 .判断手机号非空
        if (StringUtils.isEmpty(mobile)) {
            throw new BusinessException("手机号不能为空", 001);
        }

        // 2.生成验证码
        String code = RandomStringUtils.random(4, false, true);

        // 3.在服务端保存验证码，reids
        String key = RedisConstatns.AUTH_USER_REGISTER_PRE + mobile;
        redisTemplate.opsForValue().set(key, code, 60, TimeUnit.SECONDS);

        // 4.发送短信
        SmsVo smsVo = new SmsVo();
        smsVo.setPhone(mobile);
        smsVo.setCode(code);
        rabbitTemplate.convertAndSend(RabbitMQCons.INFORM_EXCHANGE, "sms.send", smsVo);
    }

    @PostMapping("/register")
    public R register(@RequestBody UserVo userVo) {
        log.debug("userVO:{}", userVo);

        // 1.获取表单的验证码
        String code = userVo.getCode();

        // 2.查询这个用户在redis的验证码
        String key = RedisConstatns.AUTH_USER_REGISTER_PRE + userVo.getPhone();
        String redisCode = redisTemplate.opsForValue().get(key);
        if (StringUtils.isEmpty(redisCode)) {
            throw new BusinessException("验证码已过期，请重新获取", 502);
        }

        // 3.对比
        if (!redisCode.equals(code)) {
            throw new BusinessException("验证码输入有误", 502);
        }

        // 4.对用户密码的加密
        userVo.setPassword(BCrypt.hashpw(userVo.getPassword(), BCrypt.gensalt()));

        // 5.注册
        R r = userService.register(userVo);
//
        return R.ok();
    }

    @PostMapping("/login")
    public R login(@RequestBody UserVo userVo, HttpSession httpSession) {

        log.debug("sessionClass:" + httpSession.getClass());
        // 1.根据用户名查询数据
        UserVo dbUserVo = userService.findUser("username", userVo.getUsername());
        if (dbUserVo == null) {
            throw new BusinessException("用户名不存在", 500);
        }

        // 2.做密码的比对
        try {
            boolean checkpw = BCrypt.checkpw(userVo.getPassword(), dbUserVo.getPassword());
            if (!checkpw) {
                throw new BusinessException("用户名获密码错误", 500);
            }
        } catch (Exception e) {
            log.error("用户密码比对失败", e);
            throw new BusinessException("用户名获密码错误", 500);
        }
        // 3.登录成功
        dbUserVo.setPassword(null);
        httpSession.setAttribute(AuthConstants.LOGIN_USER, dbUserVo);

        // 合并购车
        carService.mergeCar(dbUserVo.getId()); // MQ 1s

        // 4.响应成功
        return R.ok();
    }

    @GetMapping("/logout")
    public R logout(HttpSession session) {
        session.invalidate(); // 注销session，也会删除redis的session
        return R.ok();
    }

    @GetMapping("/getUser")
    public R getUser(HttpSession session, HttpServletRequest request) {

//
//        Cookie[] cookies = request.getCookies();
//        for (Cookie cookie : cookies) {
//            String name = cookie.getName();
//            log.debug("cookie-Name=======:{}", name);
//        }

        // 1.先获取当前登录用户
        UserVo userVo = (UserVo) session.getAttribute(AuthConstants.LOGIN_USER);

        // 2.在获取用户的购物车的数量
        Integer userCarCount = carService.getUserCarCount();
        log.debug("userCarCount:{}", userCarCount);

        // 3.创建一个Map
        Map<String, Object> map = new HashMap<>();
        map.put("userCarCount", userCarCount);
        if (userVo != null) {
            map.put("data", userVo);
        }
        return R.ok(map);
    }

    @PostMapping("/queryUser")
    public R queryUser(@RequestBody Map<String, Object> map) {
        log.debug("name:{}", map);

        if (map == null || map.isEmpty()) {
            throw new BusinessException("用户名不能为空", 500);
        }

        String name = map.get("name") + "";

        if (StringUtils.isEmpty(name)) {
            throw new BusinessException("用户名不能为空", 500);
        }

        // 查询用户是否存在
        UserVo userVo = userService.queryUser(name);
        if (userVo == null) {
            throw new BusinessException("用户不存在", 500);
        }

        // 获取用户的邮箱地址
        String email = userVo.getEmail();

        String msg = "修改密码的连接已经发送到您【%s】的邮箱，请<a href='%s'>登录</a>邮箱查看";


        // 1.获取带有*的邮箱
        String hidenEmail = getHidenEmail(email);

        // 2.获取邮箱的登录地址
        String emailLongUrl = getEmailLongUrl(email);

        // 3.格式化
        String formatMsg = String.format(msg, hidenEmail, emailLongUrl);

        // 发送邮件
        sendEmail(email, userVo);

        // 4.响应用户
        return R.ok().put("msg", formatMsg);
    }

    private void sendEmail(String e, UserVo userVo) {

        Map<String, String> map = new HashMap<>();
        map.put("id", userVo.getId().toString());
        String token = JWTUtils.createToken(map, 1000 * 60 * 10); // 10m

        String url = "http://localhost/auth/changePassword.html?token=" + token;

        // 封装发送邮箱的对象
        Email email = new Email();
        email.setTitle("2103商城用户密码修改");
        email.setContent("点击<a href ='" + url + "'>这里</a>修改密码,连接30分钟内有效，请尽快修改。");
        email.setToUserList(e);

        // 发送给MQ
        rabbitTemplate.convertAndSend(RabbitMQCons.INFORM_EXCHANGE, "email.send", email);
    }

    public String getEmailLongUrl(String email) {
        String url = "http://www.mail.%s.com";
        String substring = email.substring(email.lastIndexOf("@") + 1, email.lastIndexOf("."));
        return String.format(url, substring);
    }

    public String getHidenEmail(String email) {
        String subEmail = email.substring(4, email.lastIndexOf("@"));
        String replace = email.replace(subEmail, "*****");
        return replace;
    }

    @PostMapping("/changePassword")
    public R changePassword(@RequestBody Map<String, String> map) {

        // 1.服务端校验
        if (map == null || map.isEmpty()) {
            return R.error(500, "参数为空");
        }
        String password = map.get("password");
        String token = map.get("token");
        if (StringUtils.isEmpty(token) || StringUtils.isEmpty(password)) {
            return R.error(500, "token或者password为空");
        }

        // 2.校验token
        DecodedJWT decodedJWT = JWTUtils.checkToken(token);
        if (decodedJWT == null) {
            return R.error(500, "token校验失败");
        }

        // 3.从Token中获取userId
        String id = JWTUtils.getData(decodedJWT, "id");

        // 4.查询这个id是否存在
        UserVo userVo = userService.findUser("id", id);
        if (userVo == null) {
            return R.error(500, "用户不存在");
        }

        // 5.对密码加密
        userVo.setPassword(BCrypt.hashpw(password, BCrypt.gensalt()));

        // 6.修改密码
        userService.updateById(userVo);

        // 7.响应用户
        return R.ok();
    }
}
